#ifndef SOLVER_H
#define SOLVER_H

#include <malloc.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <glew.h>
#include <glut.h>
#include <Cg/cgGL.h>
#include <Cg/cg.h>

#pragma comment(lib,"cgGL.lib")
#pragma comment(lib,"cg.lib")
#pragma comment(lib,"glew32.lib")

using namespace std;

typedef struct  
{
	GLenum target;
	GLenum interFormat;
	GLenum format;
	GLuint type;
	int width;
	int height;
}GPUFBO;

typedef enum
{
	CG_GL_MODELVIEW_MTX,
	CG_GL_MODELVIEW_PROJECTION_MTX,
	CG_GL_MODELVIEW_IT_MTX,
	CG_GL_ARBITRARY_MTX,
	CG_GL_VECTOR_1D,
	CG_GL_VECTOR_2D,
	CG_GL_VECTOR_3D,
	CG_GL_VECTOR_4D,
	CG_GL_TEXTURE_2D,
	CG_GL_TEXTURE_RECT,
	CG_GL_TEXTURE_CUBE_MAP,
	CG_GL_VECTOR_4D_ARRAY,
} CGGL_PARAMETER_TYPE;

typedef struct  
{
	CGparameter	param;
	string		name;
	void		*ptrs;
	CGGL_PARAMETER_TYPE type;
}GPUParam;

typedef vector<GPUParam> GPUParamList;

class VideoBuffer
{
public:
	VideoBuffer(){};	
	~VideoBuffer(){};

	void BufferInit(GPUFBO &framebuffer);
	void AllocateMemory(float* data);
	void AllocateCacheMemory();
	void SwapMemory();

public:
	GLuint bufferID;
	GLuint cacheID;
	GPUFBO framebuffer;
	float *buffer;
};

class ShaderObject
{
public:
	ShaderObject();
	~ShaderObject(){};

	bool	Load(const char *filename, CGGLenum type);
	void	Unload();
	void	AddParameter(char *name, CGGL_PARAMETER_TYPE type, void *ptr);
	void	RefreshParameter();
	void	ShaderBind();
	void	ShaderRelease();

public:
	CGcontext					shaderContext;
	CGprogram					shaderProgram;
	CGprofile					shaderProfile;

	string shaderName;
	CGGLenum shaderType;

	GPUParamList				shaderParameters;
};

class FrameBufferObject
{
public:
	FrameBufferObject(){};
	~FrameBufferObject(){};
	void FBOInit(GPUFBO &framebuffer);
	void FBOActivate(GLuint &texID);
	void FBODeactivate();

public:
	GPUFBO framebuffer;
	GLuint framebufferID;
};


class Solver
{
public:
	Solver(void);
	~Solver(void);

	void SolverInit(int width, int height, GLenum interFormat, GLenum format, GLuint type, GLenum target=GL_TEXTURE_RECTANGLE_ARB);
	void SolverUpdate();
	void SolverProcessing();
	void ApplyBuoyancy();
	void ApplyVelAdvection();
	void ApplyDenAdvection();
	void AddSource();
	void GetDensity();


public:
	GPUFBO framebuffer;
	FrameBufferObject renderTarget;

	ShaderObject applyForce;
	ShaderObject vortConfine;
	ShaderObject velAdvect;
	ShaderObject velProject;
	ShaderObject velUpdate;
	ShaderObject addSource;
	ShaderObject denAdvect;
	ShaderObject denToCPU;

	VideoBuffer *density;
	VideoBuffer *velocity;
	VideoBuffer *source;

	GLfloat buoy_tamb;
	GLfloat buoy_a;
	GLfloat buoy_b;

	GLfloat dt;
};

#endif

